/*
 * resmanager.cpp
 *
 *  Created on: Oct 24, 2011
 *      Author: fferri
 */

#include "resmanager.h"
#include "Log/LogSystem.h"
#include "core/core_utils.h"
#include "vfs/vfs.h"
#include "abstractLoader.h"
#include <memory.h>
#include <boost/unordered_map.hpp>
#include "datasourceManager.h"
#include "Resource.h"
#include "resHashMap.h"

namespace lpe {
namespace resman {

	ResManager::ResManager(){}

	ResManager::~ResManager() {
		delete m_datasources;
	}

	bool ResManager::init(const std::string& configFile)
	{
		try{
			initResManLog();
			initResHashMap();
			m_datasources = new DatasourceManager();
			m_datasources->initFromXMLFile(configFile);
		}
		catch(lpe::core::fileManagementException& fme)
		{
			m_log->FATAL_MSG(RESMAN_APP,"%s: Saliendo de la aplicacion. La aplicacion ha generado una excepcion, con descripcion:\n\t %s",AT,fme.what());
			m_log->processMessages();
			throw;
		}
		return true;
	}

	bool ResManager::init(){
		return init("datasources.xml");
	}

	std::string ResManager::getRawFileByName(const std::string& datasource, const std::string& fileName)
	{
		CVirtualFileSystem* vfs = m_datasources->getVirtualFileSystemByName(datasource);
		if(vfs == NULL)
		{
			std::stringstream ss;
			ss << "Datasource " << datasource << " no existe";
			THROW_AND_LOG(RESMAN_APP,lpe::core::fileManagementException,ss.str());
			return "";
		}
		std::string result;
		try{
			result = vfs->deployFile(fileName.c_str());
		}
		catch(lpe::core::fileManagementException& lme)
		{
			THROW_AND_LOG(RESMAN_APP,lpe::core::fileNotFoundException,lme.what());
		}
		return result;
	}
	const CVirtualFileSystem* ResManager::getDataSourceByName(const std::string& dsName) const
	{
		return m_datasources->getVirtualFileSystemByName(dsName);
	}
	bool ResManager::initResManLog()
	{
		glog::CGlobalLog::initSingleton();
		m_log = &glog::CGlobalLog::getSingleton();
		m_log->addAppender(RESMAN_APP);
		m_log->addListener(new glog::CLogWriter("./resman.log", glog::LOGLEVEL_DEBUG),RESMAN_APP);
		//m_log->addListener(new glog::CConsoleWriter(glog::LOGLEVEL_DEBUG), RESMAN_APP);
		m_log->DEBUG_MSG(RESMAN_APP, "%s: Log system iniciado correctamente", AT);
		return true;
	}
	bool ResManager::initResHashMap()
	{
		m_resourceHashMap = new ResourceHashMap(RESMAN_APP);
		return true;
	}
	const uint32_t ResManager::loadResource(const std::string& datasource, const std::string& fileName)
	{
		return loadResource(datasource, fileName, new Resource);
	}
	Resource* ResManager::acquireResource(const uint32_t id)
	{
		return m_resourceHashMap->acquireResource(id);
	}
	void ResManager::releaseResource(Resource* res)
	{
		m_resourceHashMap->releaseResource(res);
	}
	bool ResManager::isResourceLoaded(const uint32_t id)
	{
		return m_resourceHashMap->isResourceLoaded(id);
	}
	const uint32_t ResManager::cloneResource(const Resource* original, Resource* cloned)
	{
		return m_resourceHashMap->cloneResource(original, cloned);
	}
	const uint32_t ResManager::loadResource(const std::string& datasource, const std::string& fileName, Resource* customResource)
	{
		uint32_t idx = 0;
		try
		{
			//primero intento asegurarme que el fichero existe en mi sistema de ficheros.
			std::string loadedRes(getRawFileByName(datasource,fileName));
			// despues llamo a resourceHashMap para cargar el fichero de metadatos dentro de un recurso.
			idx = m_resourceHashMap->loadResourceFromMetadataFile(loadedRes, customResource);
			IAbstractLoader* loader = m_loaderHashMap[customResource->getResourceType()];
			loader->loadItem(customResource->getFileName(), customResource);
		}
		catch(lpe::core::fileNotFoundException& fnf)
		{
			return 0;
		}
		return idx;
	}
	bool  ResManager::addLoader(IAbstractLoader* loader)
	{
		assert(loader != NULL); // asi evito errores raros.
		// el assert previene loaders mal inicializados
		assert(loader->getLoaderID() == 0);
		// no permitimos la substitucion directa. Si alguien quiere reemplazar, que primero haga un removeLoader y
		// despues vuelva a hacer un addLoader.
		if(m_loaderHashMap.find(loader->getLoaderID()) != m_loaderHashMap.end())
			return false;
		m_loaderHashMap[loader->getLoaderID()] = loader;
		return true;
	}
	bool  ResManager::removeLoader(IAbstractLoader* loader)
	{
		assert(loader != NULL);
		// comprobar si encontramos el loader y devolver false en caso contrario (a modo de aviso).
		if(m_loaderHashMap.find(loader->getLoaderID()) == m_loaderHashMap.end())
			return false;
		m_loaderHashMap.erase(loader->getLoaderID());
		return true;
	}

}
}
